package com.bootdo.system.service.impl;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.*;
import com.bootdo.common.config.BootdoConfig;
import com.bootdo.common.domain.FileDO;
import com.bootdo.common.service.FileService;
import com.bootdo.common.utils.*;
import com.bootdo.common.wx.HttpClientUtil;
import com.bootdo.common.wx.SignUtil;
import com.bootdo.common.wx.WxConstants;
import com.bootdo.system.service.DeptService;
import com.bootdo.system.vo.UserVO;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bootdo.common.domain.Tree;
import com.bootdo.system.dao.DeptDao;
import com.bootdo.system.dao.UserDao;
import com.bootdo.system.dao.UserRoleDao;
import com.bootdo.system.domain.DeptDO;
import com.bootdo.system.domain.UserDO;
import com.bootdo.system.domain.UserRoleDO;
import com.bootdo.system.service.UserService;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Transactional
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userMapper;
    @Autowired
    UserRoleDao userRoleMapper;
    @Autowired
    DeptDao deptMapper;
    @Autowired
    private FileService sysFileService;
    @Autowired
    private BootdoConfig bootdoConfig;
    @Autowired
    DeptService deptService;

    @Override
//    @Cacheable(value = "user",key = "#id")
    public UserDO get(Long id) {
        List<Long> roleIds = userRoleMapper.listRoleId(id);
        UserDO user = userMapper.get(id);
        if(user != null) {
        	Long deptId = user.getDeptId();
            if(deptId != null && deptId > 0) {
            	user.setDeptName(deptMapper.get(deptId).getName());
            }
            user.setRoleIds(roleIds);
        }
        return user;
    }

    @Override
    public List<UserDO> list(Map<String, Object> map) {
    	Long deptId = (Long) map.get("deptId");
        if (deptId != null) {
//            Long deptIdl = Long.valueOf(deptId);
            List<Long> childIds = deptService.listChildrenIds(deptId);
            childIds.add(deptId);
            map.put("deptId", null);
            map.put("deptIds",childIds);
        }
        return userMapper.list(map);
    }

    @Override
    public int count(Map<String, Object> map) {
        return userMapper.count(map);
    }

    @Transactional
    @Override
    public int save(UserDO user) {
        int count = userMapper.save(user);
        Long userId = user.getUserId();
        List<Long> roles = user.getRoleIds();
        userRoleMapper.removeByUserId(userId);
        List<UserRoleDO> list = new ArrayList<>();
        for (Long roleId : roles) {
            UserRoleDO ur = new UserRoleDO();
            ur.setUserId(userId);
            ur.setRoleId(roleId);
            list.add(ur);
        }
        if (list.size() > 0) {
            userRoleMapper.batchSave(list);
        }
        return count;
    }
    
    @Override
	public int saveOpenId(UserDO user) {
    	 int r=userMapper.save(user);
    	Long userId = user.getUserId();
    	userRoleMapper.removeByUserId(userId);
    	List<Long> roles = user.getRoleIds();
        List<UserRoleDO> list = new ArrayList<>();
        for (Long roleId : roles) {
            UserRoleDO ur = new UserRoleDO();
            ur.setUserId(userId);
            ur.setRoleId(roleId);
            list.add(ur);
        }
        if (list.size() > 0) {
            userRoleMapper.batchSave(list);
        }
		return r;
	}

    @Override
    public int update(UserDO user) {
        int r = userMapper.update(user);
        Long userId = user.getUserId();
        List<Long> roles = user.getRoleIds();
        userRoleMapper.removeByUserId(userId);
        List<UserRoleDO> list = new ArrayList<>();
        for (Long roleId : roles) {
            UserRoleDO ur = new UserRoleDO();
            ur.setUserId(userId);
            ur.setRoleId(roleId);
            list.add(ur);
        }
        if (list.size() > 0) {
            userRoleMapper.batchSave(list);
        }
        return r;
    }

    //    @CacheEvict(value = "user")
    @Override
    public int remove(Long userId) {
        userRoleMapper.removeByUserId(userId);
        return userMapper.remove(userId);
    }

    @Override
    public boolean exit(Map<String, Object> params) {
        boolean exit;
        exit = userMapper.list(params).size() > 0;
        return exit;
    }

    @Override
    public Set<String> listRoles(Long userId) {
        return null;
    }

    @Override
    public int resetPwd(UserVO userVO, UserDO userDO) throws Exception {
        if (Objects.equals(userVO.getUserDO().getUserId(), userDO.getUserId())) {
            if (Objects.equals(MD5Utils.encrypt(userDO.getUsername(), userVO.getPwdOld()), userDO.getPassword())) {
                userDO.setPassword(MD5Utils.encrypt(userDO.getUsername(), userVO.getPwdNew()));
                return userMapper.update(userDO);
            } else {
                throw new Exception("输入的旧密码有误！");
            }
        } else {
            throw new Exception("你修改的不是你登录的账号！");
        }
    }

    @Override
    public int adminResetPwd(UserVO userVO) throws Exception {
        UserDO userDO = get(userVO.getUserDO().getUserId());
        if ("admin".equals(userDO.getUsername())) {
            throw new Exception("超级管理员的账号不允许直接重置！");
        }
        userDO.setPassword(MD5Utils.encrypt(userDO.getUsername(), userVO.getPwdNew()));
        return userMapper.update(userDO);


    }

    @Transactional
    @Override
    public int batchremove(Long[] userIds) {
        int count = userMapper.batchRemove(userIds);
        userRoleMapper.batchRemoveByUserId(userIds);
        return count;
    }

    @Override
    public Tree<DeptDO> getTree() {
        List<Tree<DeptDO>> trees = new ArrayList<Tree<DeptDO>>();
        List<DeptDO> depts = deptMapper.list(new HashMap<String, Object>(16));
        Long[] pDepts = deptMapper.listParentDept();
        Long[] uDepts = userMapper.listAllDept();
        Long[] allDepts = (Long[]) ArrayUtils.addAll(pDepts, uDepts);
        for (DeptDO dept : depts) {
            if (!ArrayUtils.contains(allDepts, dept.getDeptId())) {
                continue;
            }
            Tree<DeptDO> tree = new Tree<DeptDO>();
            tree.setId(dept.getDeptId().toString());
            tree.setParentId(dept.getParentId().toString());
            tree.setText(dept.getName());
            Map<String, Object> state = new HashMap<>(16);
            state.put("opened", true);
            state.put("mType", "dept");
            tree.setState(state);
            trees.add(tree);
        }
        List<UserDO> users = userMapper.list(new HashMap<String, Object>(16));
        for (UserDO user : users) {
            if(user.getDeptId() != null) {
            	Tree<DeptDO> tree = new Tree<DeptDO>();
                tree.setId(user.getUserId().toString());
            	tree.setParentId(user.getDeptId().toString());
            	tree.setText(user.getName());
                Map<String, Object> state = new HashMap<>(16);
                state.put("opened", true);
                state.put("mType", "user");
                tree.setState(state);
                trees.add(tree);
            }
        }
        // 默认顶级菜单为０，根据数据库实际情况调整
        Tree<DeptDO> t = BuildTree.build(trees);
        return t;
    }

    @Override
    public int updatePersonal(UserDO userDO) {
    	UserDO userByUserName = getUserByUserName(userDO.getUsername());
    	if(userByUserName != null) {
    		Long userId = userByUserName.getUserId();
    		Long userId2 = userDO.getUserId();
    		if(userId == userId2) {
    			return userMapper.update(userDO);
    		}else {
    			return 0;
    		}
    	}else {
    		String encrypt = MD5Utils.encrypt(userDO.getUsername(), "000000");
    		userDO.setPassword(encrypt);
    		return userMapper.update(userDO);
    	}
    }

    @Override
    public Map<String, Object> updatePersonalImg(MultipartFile file, String avatar_data, Long userId) throws Exception {
        String fileName = file.getOriginalFilename();
        fileName = FileUtil.renameToUUID(fileName);
        FileDO sysFile = new FileDO(FileType.fileType(fileName), "/files/" + fileName, new Date());
        //获取图片后缀
        String prefix = fileName.substring((fileName.lastIndexOf(".") + 1));
        String[] str = avatar_data.split(",");
        //获取截取的x坐标
        int x = (int) Math.floor(Double.parseDouble(str[0].split(":")[1]));
        //获取截取的y坐标
        int y = (int) Math.floor(Double.parseDouble(str[1].split(":")[1]));
        //获取截取的高度
        int h = (int) Math.floor(Double.parseDouble(str[2].split(":")[1]));
        //获取截取的宽度
        int w = (int) Math.floor(Double.parseDouble(str[3].split(":")[1]));
        //获取旋转的角度
        int r = Integer.parseInt(str[4].split(":")[1].replaceAll("}", ""));
        try {
            BufferedImage cutImage = ImageUtils.cutImage(file, x, y, w, h, prefix);
            BufferedImage rotateImage = ImageUtils.rotateImage(cutImage, r);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            boolean flag = ImageIO.write(rotateImage, prefix, out);
            //转换后存入数据库
            byte[] b = out.toByteArray();
            FileUtil.uploadFile(b, bootdoConfig.getUploadPath(), fileName);
        } catch (Exception e) {
            throw new Exception("图片裁剪错误！！");
        }
        Map<String, Object> result = new HashMap<>();
        if (sysFileService.save(sysFile) > 0) {
            UserDO userDO = new UserDO();
            userDO.setUserId(userId);
            userDO.setPicId(sysFile.getId());
            if (userMapper.update(userDO) > 0) {
                result.put("url", sysFile.getUrl());
            }
        }
        return result;
    }

    @Override
    public void doWxLogin(HttpServletRequest request, HttpServletResponse response) throws IOException{
 
        String authUrl = WxConstants.AUTH_BASE_URL + "appid=" + WxConstants.APPID
                + "&redirect_uri=" + URLEncoder.encode(WxConstants.REDIRECT_URL)
                + "&response_type=code"
                + "&scope=" + WxConstants.SCOPE
                + "&state=STATE#wechat_redirect";
        String signature = request.getParameter("signature");/// 微信加密签名
        String timestamp = request.getParameter("timestamp");/// 时间戳
        String nonce = request.getParameter("nonce"); /// 随机数
        String echostr = request.getParameter("echostr"); // 随机字符串
 
        PrintWriter out = response.getWriter();
        if (signature != null && timestamp != null && nonce != null && echostr != null) {
            if (SignUtil.checkSignature(signature, timestamp, nonce)) {
                out.print(echostr);
            }
            out.close();
        } else {
            response.sendRedirect(authUrl);
        }
    }    

    
    
    
    public Result doWxCallBack(String code, HttpServletRequest request, HttpServletResponse response) throws  Exception{
        //通过code换取网页授权access_token
        String access_token_url = WxConstants.ACCESS_TOKEN_BASE_URL
                + "appid=" + WxConstants.APPID
                + "&secret=" + WxConstants.APPSECRET
                + "&code=" + code
                + "&grant_type=authorization_code";
 
        //发送请求
        String jsonResult = HttpClientUtil.doGet(access_token_url);
        if (jsonResult == null || "".equals(jsonResult)) {
            return Result.error(CodeMsg.USER_RZSB);
        }
        JsonObject accessJsonObject = new JsonParser().parse(jsonResult).getAsJsonObject();
        //与开放平台关联要使用unionid
        String openid = accessJsonObject.get("openid").getAsString();
        String access_token = accessJsonObject.get("access_token").getAsString();
        /**
         * 微信与用户信息的绑定
         */
        UserDO user = userMapper.getUserInfoByOpenid(openid);
        if (user == null) {
            //先登录，然后执行绑定授权操作
            return Result.error(CodeMsg.USER_DLSQ);
        }
 
        /**
         * 获取用户的微信信息(需scope为 snsapi_userinfo)
         */
        String infoUrl = WxConstants.INFO_BASE_URL
                + "access_token=" + access_token
                + "&openid=" + openid
                + "&lang=zh_CN";
        String userInfoJson = HttpClientUtil.doGet(infoUrl);
        if (userInfoJson == null || "".equals(userInfoJson)) {
            return Result.error(CodeMsg.USER_HQYHSB);
        }
        //使用微信的信息
        JsonObject userInfoJsonObject = new JsonParser().parse(userInfoJson).getAsJsonObject();
 
        //返回用户信息
        List infoList = new ArrayList<>();
        infoList.add(userInfoJsonObject);
        infoList.add(user);
        //保存用户信息 测试使用  应加入shiro认证
//        userInfoMap.put(user.getUsername(), infoList);
        return Result.success(user.getUsername());
    }

	@Override
	public UserDO getUserByOpenId(String openId) {
		return userMapper.getUserByOpenId(openId);
	}


	@Override
	public UserDO getUserByUserName(String username) {
		return userMapper.getUserByUserName(username);
	}

	@Override
	public int update2(UserDO user) {
		user.setPassword(MD5Utils.encrypt(user.getUsername(),user.getPassword()));
		return userMapper.update(user);
	}

	@Override
	public int updateZfb(UserDO userDO) {
		return userMapper.update(userDO);
	}

	@Override
	public List<UserDO> list2(Map<String, Object> map) {
		String deptId = (String) map.get("deptId");
        if (StringUtils.isNoneBlank(deptId)) {
            Long deptIdl = Long.valueOf(deptId);
            List<Long> childIds = deptService.listChildrenIds(deptIdl);
            childIds.add(deptIdl);
            map.put("deptId", null);
            map.put("deptIds",childIds);
        }
        return userMapper.list(map);
	}

	@Override
	public int update3(UserDO user) {
		user.setPassword(MD5Utils.encrypt(user.getUsername(),user.getPassword()));
		 int r = userMapper.update(user);
        Long userId = user.getUserId();
        List<Long> roles = user.getRoleIds();
        userRoleMapper.removeByUserId(userId);
        List<UserRoleDO> list = new ArrayList<>();
        for (Long roleId : roles) {
            UserRoleDO ur = new UserRoleDO();
            ur.setUserId(userId);
            ur.setRoleId(roleId);
            list.add(ur);
        }
        if (list.size() > 0) {
            userRoleMapper.batchSave(list);
        }
        return r;
	}

	@Override
	public List<Long> getIdByDeptId(Long deptId) {
		return userMapper.getIdByDeptId(deptId);
	}

	@Override
	public int update4(UserDO user) {
		return userMapper.update(user);
	}
}
